﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Runtime.CompilerServices;
using System.Windows.Forms;


namespace Marmat.Forms
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(System.Windows.Forms.TreeView))]
    public partial class TreeView : Skin.ScrollControl
    {
        public TreeView()
        {

            // 此调用是设计器所必需的。
            this.InitializeComponent();

            // 在 InitializeComponent() 调用之后添加任何初始化。
        }

        [DefaultValue(null)]
        public TreeNode SelectedNode
        {
            get
            {
                return this.m_SelectedNode;
            }

            set
            {
                if (this.SelectedNode is object)
                {
                    this.Invalidate(this.SelectedNode.Bounds);
                }

                this.m_SelectedNode = value;
                if (this.SelectedNode is object)
                {
                    this.Invalidate(this.SelectedNode.Bounds);
                }
            }
        }

        private TreeNode m_SelectedNode;

        /// <summary>
        /// Table中的列集合。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Editor(typeof(TreeViewEditor), typeof(UITypeEditor))]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Localizable(true)]
        [NotifyParentProperty(true)]
        [Category("数据")]
        [Description("返回 Table 的列集合")]
        public TreeNodeCollection Nodes
        {
            get
            {
                if (this.m_Nodes is null)
                {
                    this.m_Nodes = new TreeNodeCollection(this, null);
                }

                return this.m_Nodes;
            }
        }

        private TreeNodeCollection m_Nodes;

        /// <summary>
        /// 指示是否在父节点显示加/减按钮。
        /// </summary>
        /// <returns></returns>
        [DefaultValue(true)]
        public bool ShowPlusMinus { get; set; } = true;

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            var Renderer = this.Renderer;
            if (Renderer is null)
            {
                Renderer = new TreeViewRenderer(this);
            }
            var EventArgs = new DrawTreeNodeEventArgs();
            EventArgs.Nodes = this.Nodes;
            EventArgs.Graphics = e.Graphics;
            EventArgs.DrawPoint = new Point(-this.HorizontalScroll.Value, -this.VerticalScroll.Value);
            Renderer.RaiseOnPaint(e);
            var Point = this.DrawTreeNode(EventArgs).DrawPoint;
            this.AutoScrollMinSize = new Size(Point.X + this.HorizontalScroll.Value, Point.Y + this.VerticalScroll.Value);
        }

        [DefaultValue(null)]
        public TreeViewRenderer Renderer { get; set; }

        private DrawTreeNodeEventArgs DrawTreeNode(DrawTreeNodeEventArgs e)
        {
            var Renderer = this.Renderer;
            if (Renderer is null)
            {
                Renderer = new TreeViewRenderer(this);
            }

            var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
            foreach (TreeNode Item in e.Nodes)
            {
                int m_Width = 3;
                string Text = !string.IsNullOrEmpty(Item.Text) ? Item.Text : Item.Name;
                var rect = new Rectangle(Item.Level * this.Indent, e.DrawPoint.Y, this.Width - 1, this.ItemHeight);
                var Size = TextRenderer.MeasureText(Text, this.Font, rect.Size, flags);
                var Rectangle = new Rectangle(0, e.DrawPoint.Y, this.Width, this.ItemHeight);

                // 绘制节点背景时发生，这里可以动态调整节点的矩形============================
                var EventArgs = new PaintTreeNodeEventArgs(Item, e.Graphics, Rectangle);
                Renderer.RaiseOnTreeNodePaint(EventArgs);
                Item.m_Rectangle = new Rectangle(rect.X, rect.Y, this.Width, EventArgs.Height == -1 ? rect.Height : EventArgs.Height);

                // '绘制线条=========================================================
                // Dim PrevNode As TreeNode = Item.PrevNode
                // Dim NextNode As TreeNode = Item.NextNode
                // If NextNode IsNot Nothing Then
                // Using Pen As New Pen(Brushes.Black)
                // Pen.DashStyle = Drawing2D.DashStyle.Dot
                // nd.PaintEventArgs.Graphics.DrawLine(Pen, rect.X + 5, CInt(rect.Y + rect.Height / 2), rect.X + 5, CInt(NextNode.Bounds.Y + NextNode.Bounds.Height / 2))
                // End Using
                // End If

                // 绘制展开符号=========================================================
                if (this.ShowPlusMinus && Item.Nodes.Count > 0)
                {
                    Image Image = Properties.Resources.treeView_fold;
                    if (Item.IsExpanded == true)
                    {
                        Image = Properties.Resources.treeView_unfold;
                    }

                    Item.Rect_ShowPlusMinus = new Rectangle(rect.X + m_Width, (int)Math.Round(rect.Y + (rect.Height - Image.Height) / 2d), Image.Width, Image.Height);
                    var f = new PaintShowPlusMinusEventArgs();
                    f.Node = Item;
                    f.Image = Image;
                    Renderer.RaiseOnPlusMinusPaint(f);
                    if (f.Image is object)
                    {
                        Item.Rect_ShowPlusMinus = new Rectangle(rect.X + m_Width, (int)Math.Round(rect.Y + (rect.Height - f.Image.Height) / 2d), f.Image.Width, f.Image.Height);
                        e.Graphics.DrawImage(Image, Item.Rect_ShowPlusMinus);
                    }

                    m_Width += Item.Rect_ShowPlusMinus.Width + 3;
                }

                // 绘制复选框=========================================================
                if (this.CheckBoxes)
                {
                    Image Image = Properties.Resources.Checked_False_normal;
                    if (Item.Checked && ReferenceEquals(Item, this.MouseMoveNode))
                    {
                        Image = Properties.Resources.Checked_True_highlight;
                    }
                    else if (Item.Checked && !ReferenceEquals(Item, this.MouseMoveNode))
                    {
                        Image = Properties.Resources.Checked_True_normal;
                    }
                    else if (Item.Checked == false && ReferenceEquals(Item, this.MouseMoveNode))
                    {
                        Image = Properties.Resources.Checked_False_hightlight;
                    }

                    var CheckBoxes = new TreeViewPaintCheckBoxesEventArgs();
                    CheckBoxes.Node = Item;
                    CheckBoxes.Image = Image;
                    Renderer.RaiseOnCheckBoxes(CheckBoxes);
                    if (CheckBoxes.Image is object)
                    {
                        Item.Rect_Checked = new Rectangle(rect.X + m_Width, (int)Math.Round(rect.Y + (rect.Height - CheckBoxes.Image.Height) / 2d), CheckBoxes.Image.Width, CheckBoxes.Image.Height);
                        e.Graphics.DrawImage(CheckBoxes.Image, Item.Rect_Checked);
                        m_Width += Item.Rect_Checked.Width;
                    }
                }

                // 绘制图片=====================================================================
                if (Item.Image is object)
                {
                    Item.Rect_Image = new Rectangle(rect.X + m_Width, (int)Math.Round(rect.Y + (rect.Height - Item.Image.Height) / 2d), Item.Image.Width, Item.Image.Height);
                    e.Graphics.DrawImage(Item.Image, Item.Rect_Image);
                    m_Width += Item.Rect_Image.Width;
                }
                // 绘制背景=====================================================================
                Item.rect_Text = new Rectangle(rect.X + m_Width, rect.Y, Size.Width, rect.Height);
                var BackColor = Color.Transparent;
                if (ReferenceEquals(Item, this.SelectedNode))
                {
                    BackColor = Color.FromArgb(51, 153, 255);
                }

                if (this.TextBox is null || !ReferenceEquals(this.TextBox.Tag, Item))
                {
                    if (BackColor != Color.Transparent)
                    {
                        using (var Brush = new SolidBrush(BackColor))
                        {
                            e.Graphics.FillRectangle(Brush, Item.rect_Text);
                        }
                    }
                }

                // 绘制标题=====================================================================
                var ForeColor = this.ForeColor;
                if (ReferenceEquals(Item, this.SelectedNode))
                {
                    ForeColor = Color.White;
                }

                var Font = this.Font;
                if (this.HotTracking && ReferenceEquals(Item, this.MouseMoveNode))
                {
                    Font = new Font(Font.FontFamily, Font.Size, FontStyle.Underline);
                }

                if (this.TextBox is null || !ReferenceEquals(this.TextBox.Tag, Item))
                {
                    TextRenderer.DrawText(e.Graphics, Text, Font, Item.rect_Text, ForeColor, Color.Transparent, flags);
                    // Using Brush As New SolidBrush(ForeColor)
                    // e.Graphics.DrawString(Text, Font, Brush, Item.Rect_Text, Format)
                    // End Using

                }

                m_Width += Item.rect_Text.Width;

                // =======================
                Item.m_Bounds = new Rectangle(rect.X, rect.Y, m_Width, rect.Height);
                // e.Graphics.DrawRectangle(Pens.Red, Item.Rectangle)

                e.DrawPoint = new Point(Item.Rectangle.X, Item.Rectangle.Bottom);
                if (Item.IsExpanded)
                {
                    var m_EventArgs = new DrawTreeNodeEventArgs();
                    m_EventArgs.Nodes = Item.Nodes;
                    m_EventArgs.Graphics = e.Graphics;
                    m_EventArgs.DrawPoint = e.DrawPoint;
                    e = this.DrawTreeNode(m_EventArgs);
                }
            }

            return e;
        }

        internal TreeNode MouseMoveNode
        {
            get
            {
                return this.m_MouseMoveNode;
            }

            set
            {
                if (this.MouseMoveNode is object)
                {
                    this.Invalidate(this.MouseMoveNode.Bounds);
                }

                this.m_MouseMoveNode = value;
                if (this.MouseMoveNode is object)
                {
                    this.Invalidate(this.MouseMoveNode.Bounds);
                }
            }
        }

        private TreeNode m_MouseMoveNode;

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            TreeNode MouseMoveNode = null;
            var Items = this.GetAllTreeNode();
            foreach (TreeNode Item in Items)
            {
                if (Item.Parent is null || Item.Parent.IsExpanded == true)
                {
                    if (Item.rect_Text != default && Item.rect_Text.Contains(e.Location) || Item.Rect_Image != default && Item.Rect_Image.Contains(e.Location) || Item.Rect_Checked != default && Item.Rect_Checked.Contains(e.Location))
                    {
                        MouseMoveNode = Item;
                        break;
                    }
                }
            }

            this.MouseMoveNode = MouseMoveNode;
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            bool boo = false;
            TreeNode selectedNode = null;
            var items = this.GetAllTreeNode();
            foreach (TreeNode Item in items)
            {
                if (Item.Parent is null || Item.Parent.IsExpanded == true)
                {
                    if (Item.Rect_Checked != default && Item.Rect_Checked.Contains(e.Location))
                    {
                        Item.Checked = !Item.Checked;
                        break;
                    }
                    else if (Item.Rect_ShowPlusMinus != default && Item.Rect_ShowPlusMinus.Contains(e.Location))
                    {
                        Item.m_IsExpanded = !Item.m_IsExpanded;
                        break;
                    }
                    else if (Item.rect_Text != default && Item.rect_Text.Contains(e.Location))
                    {
                        selectedNode = Item;
                        boo = true;
                        break;
                    }
                    else if (Item.Rect_Image != default && Item.Rect_Image.Contains(e.Location))
                    {
                        selectedNode = Item;
                        break;
                    }
                }
            }

            if (boo && selectedNode is object && ReferenceEquals(selectedNode, this.SelectedNode))
            {
                this.EditTreeNode(selectedNode);
            }
            else if (this.TextBox is object)
            {
                this.TextBox_Validated(this.TextBox, new EventArgs());
                var EventArgs = new TreeViewEventArgs(selectedNode, TreeViewAction.ByMouse);
                AfterSelect?.Invoke(this, EventArgs);
            }

            this.SelectedNode = selectedNode;
        }

        /// <summary>
        /// 编辑目录树节点
        /// </summary>
        /// <param name="nd"></param>
        /// <remarks></remarks>
        private void EditTreeNode(TreeNode nd)
        {
            if (this.LabelEdit == true)
            {
                if (this.TextBox is null)
                {
                    this.TextBox = new System.Windows.Forms.TextBox();
                    this.TextBox.Visible = false;
                    this.Controls.Add(this.TextBox);
                }

                this.TextBox.Location = nd.rect_Text.Location;
                this.TextBox.Size = nd.rect_Text.Size;
                this.TextBox.Font = this.Font;
                this.TextBox.Visible = true;
                this.TextBox.Text = nd.Text;
                this.TextBox.Tag = nd;
            }
        }

        private System.Windows.Forms.TextBox _TextBox;

        protected internal System.Windows.Forms.TextBox TextBox
        {
            [MethodImpl(MethodImplOptions.Synchronized)]
            get => _TextBox;
            [MethodImpl(MethodImplOptions.Synchronized)]
            set
            {
                if (_TextBox != null)
                {
                    _TextBox.KeyPress -= TextBox_KeyPress;
                    _TextBox.TextChanged -= TextBox_TextChanged;
                    _TextBox.Validated -= TextBox_Validated;
                }

                _TextBox = value;
                if (_TextBox != null)
                {
                    _TextBox.KeyPress += TextBox_KeyPress;
                    _TextBox.TextChanged += TextBox_TextChanged;
                    _TextBox.Validated += TextBox_Validated;
                }
            }
        }

        private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\u001b')
            {
                this.TextBox.Visible = false;
                this.TextBox.Tag = null;
                e.Handled = true;
            }
        }

        private void TextBox_TextChanged(object sender, EventArgs e)
        {
            if (this.TextBox.Tag is object)
            {
                string Text = this.TextBox.Text;
                if (string.IsNullOrEmpty(Text))
                    Text = ".";
                int Width = TextRenderer.MeasureText(Text, this.Font, this.Size, TextFormatFlags.TextBoxControl | TextFormatFlags.LeftAndRightPadding).Width;
                if (this.TextBox.Left + Width > this.Width)
                {
                    this.TextBox.Width = this.Width - this.TextBox.Left;
                }
                else
                {
                    this.TextBox.Width = Width;
                }
            }
        }

        private void TextBox_Validated(object sender, EventArgs e)
        {
            if (sender is TextBox textbox && textbox.Tag is object)
            {
                ((TreeNode)textbox.Tag).Text = textbox.Text;
                textbox.Visible = false;
            }
            this.TextBox.Tag = null;
        }

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            var Items = this.GetAllTreeNode();
            foreach (TreeNode Item in Items)
            {
                if (Item.Parent is null || Item.Parent.IsExpanded == true)
                {
                    if (Item.Rect_Checked != default && Item.Rect_Checked.Contains(e.Location))
                    {
                        break;
                    }
                    else if (Item.rect_Text != default && Item.rect_Text.Contains(e.Location) || Item.Rect_Image != default && Item.Rect_Image.Contains(e.Location))
                    {
                        if (Item.Nodes.Count > 0)
                        {
                            Item.m_IsExpanded = !Item.IsExpanded;
                            break;
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 重写 System.ComponentModel.Component.ToString。
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public override string ToString()
        {
            return default;
        }


        /// <summary>
        /// 获取目录树节点下的所有节点
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public List<TreeNode> GetAllTreeNode()
        {
            return this.BaseGetAllTreeNode(this.Nodes);
        }
        /// <summary>
        /// 获取目录节点下的所有节点
        /// </summary>
        /// <param name="TreeNode"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public List<TreeNode> GetAllTreeNode(TreeNode TreeNode)
        {
            return this.BaseGetAllTreeNode(TreeNode.Nodes);
        }

        /// <summary>
        /// 获取目录节点下的所有节点
        /// </summary>
        /// <param name="Collection"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        private List<TreeNode> BaseGetAllTreeNode(TreeNodeCollection Collection)
        {
            var Items = new List<TreeNode>();
            foreach (TreeNode Item in Collection)
            {
                Items.Add(Item);
                this.BaseChildGetAllTreeNode(Items, Item);
            }

            return Items;
        }

        private void BaseChildGetAllTreeNode(List<TreeNode> Items, TreeNode TreeNode)
        {
            foreach (TreeNode Item in TreeNode.Nodes)
            {
                Items.Add(Item);
                this.BaseChildGetAllTreeNode(Items, Item);
            }
        }
    }
}